package com.hilinos.common.util;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.util.DigestUtils;

import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author qhl
 */
@Slf4j
public class RequestUtils {

    public static final MediaType MEDIA_TYPE_APPLICATION_JSON = MediaType.parse("application/json");
    public static final MediaType MEDIA_TYPE_TEXT_PLAIN = MediaType.parse("text/plain");

    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectionPool(new ConnectionPool(20, 1, TimeUnit.MINUTES))
            .writeTimeout(15, TimeUnit.SECONDS)
            .readTimeout(15, TimeUnit.SECONDS)
            .connectTimeout(15, TimeUnit.SECONDS)
            .build();

    /**
     * post提交
     *
     * @param url
     * @param mediaType
     * @param body
     * @param header
     * @return
     */
    public static String post(String url, MediaType mediaType, String body, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .post(RequestBody.create(mediaType, body))
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  mediaType:{}  header:{}  body:{}  result:{}", url, mediaType.toString(), header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  mediaType:{}  header:{}  body:{}", url, mediaType.toString(), header, body);
            }
        }
        return result;
    }

    /**
     * put提交
     *
     * @param url
     * @param mediaType
     * @param body
     * @param header
     * @return
     */
    public static String put(String url, MediaType mediaType, String body, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .put(RequestBody.create(mediaType, body))
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  mediaType:{}  header:{}  body:{}  result:{}", url, mediaType.toString(), header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  mediaType:{}  header:{}  body:{}", url, mediaType.toString(), header, body);
            }
        }
        return result;
    }

    /**
     * put提交
     *
     * @param url
     * @param header
     * @return
     */
    public static String delete(String url, Map<String, String> header) {
        boolean isSuccess = false;
        String result = null;
        try {
            Request.Builder builder = new Request.Builder()
                    .delete()
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  header:{}  result:{}", url, header, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  header:{}  ", url, header);
            }
        }
        return result;
    }

    /**
     * post提交
     *
     * @param url
     * @param body
     * @param header
     * @return
     */
    public static String postForm(String url, Map<String, String> header, Map<String, String> body) {
        boolean isSuccess = false;
        String result = null;
        try {
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            if (body != null) {
                body.forEach(bodyBuilder::add);
            }
            Request.Builder builder = new Request.Builder()
                    .post(bodyBuilder.build())
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            isSuccess = true;
            result = response.body().string();
            return result;
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
            isSuccess = false;
        } finally {
            if (isSuccess) {
                log.info("[网络请求]请求成功 url:{}  header:{}  body:{}  result:{}", url, header, body, result);
            } else {
                log.info("[网络请求]请求失败 url:{}  header:{}  body:{}", url, header, body);
            }
        }
        return result;
    }

    /**
     * get提交
     */
    public static String get(String url, Map<String, String> header) {
        try {
            Request.Builder builder = new Request.Builder()
                    .get()
                    .url(url);
            if (header != null) {
                header.forEach(builder::header);
            }
            Response response = CLIENT.newCall(builder.build()).execute();
            String responseStr = response.body().string();
            log.info("请求成功 url:{}", url);
            return responseStr;
        } catch (Exception e) {
            log.info("[网络请求]请求失败");
        }
        return null;
    }

    /**
     * 摘要认证请求
     *
     * @param user
     * @param password
     * @param url
     * @param json
     * @return
     * @throws Exception
     */
    public static String postJsonDigestAuth(String user, String password, String url, String json) throws Exception {
        if (log.isInfoEnabled()) {
            log.info("[网络请求]接口开始访问: user = {} , password = {} , url = {} , json = {}", user, password, url, json);
        }
        String uri = new URL(url).getPath();
        Response response = CLIENT.newCall(new Request.Builder()
                .get().url(url)
                .build()).execute();
        if (response.code() != 401) {
            return null;
        }
        String wwwAuth = response.header("WWW-Authenticate");
        String realm = wwwAuth.split("realm=\"")[1].split("\"")[0];
        String qop = wwwAuth.split("qop=\"")[1].split("\"")[0];
        String nonce = wwwAuth.split("nonce=\"")[1].split("\"")[0];
        String opaque = wwwAuth.split("opaque=\"")[1].split("\"")[0];
        String nc = "00000001";
        response.close();
        String cn = "" + System.currentTimeMillis();
        String ha1 = DigestUtils.md5DigestAsHex((user + ":" + realm + ":" + password).getBytes());
        String ha2 = DigestUtils.md5DigestAsHex(("POST" + ":" + uri).getBytes());
        String resp = ha1 +
                ":" + nonce +
                ":" + nc +
                ":" + cn +
                ":" + qop +
                ":" + ha2;
        String respEncodeStr = DigestUtils.md5DigestAsHex(resp.getBytes());

        StringBuilder sb = new StringBuilder();
        sb.append("Digest ");
        sb.append("username=\"").append(user).append("\",");
        sb.append("realm=\"").append(realm).append("\",");
        sb.append("nonce=\"").append(nonce).append("\",");
        sb.append("uri=\"").append(uri).append("\",");
        sb.append("cnonce=\"").append(cn).append("\",");
        sb.append("nc=\"").append(nc).append("\",");
        sb.append("algorithm=\"").append("MD5").append("\",");
        sb.append("response=\"").append(respEncodeStr).append("\",");
        sb.append("qop=\"").append(qop).append("\",");
        sb.append("opaque=\"").append(opaque).append("\"");
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", sb.toString());
        String result = post(
                url,
                MEDIA_TYPE_APPLICATION_JSON,
                json,
                headers
        );
        if (log.isInfoEnabled()) {
            log.info("[网络请求]接口访问结束: \nuser = {}\npassword = {}\nurl = {}\njson = {}\nresult = {}", user, password, url, json, result);
        }
        return result;
    }
}
